package com.example.wenmini.service.humanlike;

import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

@Component
public class HumanLikeOperator {
    private static final Logger log = LoggerFactory.getLogger(HumanLikeOperator.class);
    private static final Random random = new Random();
    
    private WebDriver driver;
    private int typingSpeed = 100;
    private BezierParams trajectoryParams;
    
    public void handleSmartVerification(WebDriver driver) {
        this.driver = driver;
        try {
            WebElement verifyBtn = findVerifyButton();
            if (verifyBtn == null) {
                log.warn("未找到验证按钮");
                return;
            }
            
            // 生成随机轨迹
            Point start = new Point(50 + random.nextInt(100), 50 + random.nextInt(100));
            Point end = getElementCenter(verifyBtn);
            BezierCurve curve = new BezierCurve(start, end);
            
            // 执行人类化移动
            Actions actions = new Actions(driver);
            actions.moveToElement(verifyBtn).perform();
            
            for (Point p : curve.getPoints(50)) {
                ((JavascriptExecutor) driver).executeScript(
                    "window.dispatchEvent(new MouseEvent('mousemove', {" +
                    "clientX: arguments[0]," +
                    "clientY: arguments[1]," +
                    "bubbles: true" +
                    "}))", p.x, p.y
                );
                randomDelay(5, 15);
            }
            
            // 随机偏移点击
            Point clickPoint = getElementCenter(verifyBtn);
            clickPoint.x += ThreadLocalRandom.current().nextInt(-3, 4);
            clickPoint.y += ThreadLocalRandom.current().nextInt(-3, 4);
            
            ((JavascriptExecutor) driver).executeScript(
                "arguments[0].dispatchEvent(new MouseEvent('mousedown', {" +
                "bubbles: true," +
                "cancelable: true," +
                "view: window," +
                "clientX: arguments[1]," +
                "clientY: arguments[2]" +
                "}));" +
                "arguments[0].dispatchEvent(new MouseEvent('mouseup', {" +
                "bubbles: true," +
                "cancelable: true," +
                "view: window," +
                "clientX: arguments[1]," +
                "clientY: arguments[2]" +
                "}));" +
                "arguments[0].click();",
                verifyBtn, clickPoint.x, clickPoint.y
            );
            
            // 验证后随机移动
            randomMouseMovement(2000);
            
        } catch (Exception e) {
            log.error("验证处理失败", e);
            throw new RuntimeException("验证处理失败", e);
        }
    }
    
    private WebElement findVerifyButton() {
        String[] selectors = {
            "#smart_verify_button",
            ".verify-btn",
            "[class*='verify'][class*='button']",
            "[id*='verify'][id*='button']"
        };
        
        for (String selector : selectors) {
            try {
                WebElement element = driver.findElement(By.cssSelector(selector));
                if (element.isDisplayed()) {
                    return element;
                }
            } catch (Exception ignored) {}
        }
        return null;
    }
    
    private Point getElementCenter(WebElement element) {
        Rectangle rect = element.getRect();
        return new Point(
            rect.x + rect.width / 2,
            rect.y + rect.height / 2
        );
    }
    
    private void randomDelay(int minMs, int maxMs) {
        try {
            // 确保最小延迟为100毫秒（0.1秒）
            int actualMinMs = Math.max(100, minMs);
            int actualMaxMs = Math.max(actualMinMs, maxMs);
            Thread.sleep(actualMinMs + random.nextInt(actualMaxMs - actualMinMs + 1));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private void randomMouseMovement(int duration) {
        long endTime = System.currentTimeMillis() + duration;
        while (System.currentTimeMillis() < endTime) {
            Point p = new Point(
                random.nextInt(800),
                random.nextInt(600)
            );
            new Actions(driver)
                .moveByOffset(p.x, p.y)
                .perform();
            randomDelay(100, 300);
        }
    }
    
    private static class BezierCurve {
        private final Point start;
        private final Point end;
        private final Point control1;
        private final Point control2;
        
        public BezierCurve(Point start, Point end) {
            this.start = start;
            this.end = end;
            
            // 生成随机控制点
            int midX = (start.x + end.x) / 2;
            int midY = (start.y + end.y) / 2;
            
            this.control1 = new Point(
                midX + random.nextInt(100) - 50,
                midY + random.nextInt(100) - 50
            );
            
            this.control2 = new Point(
                midX + random.nextInt(100) - 50,
                midY + random.nextInt(100) - 50
            );
        }
        
        public Point[] getPoints(int count) {
            Point[] points = new Point[count];
            for (int i = 0; i < count; i++) {
                double t = i / (double) (count - 1);
                points[i] = getPoint(t);
            }
            return points;
        }
        
        private Point getPoint(double t) {
            double x = Math.pow(1-t, 3) * start.x +
                      3 * Math.pow(1-t, 2) * t * control1.x +
                      3 * (1-t) * Math.pow(t, 2) * control2.x +
                      Math.pow(t, 3) * end.x;
                      
            double y = Math.pow(1-t, 3) * start.y +
                      3 * Math.pow(1-t, 2) * t * control1.y +
                      3 * (1-t) * Math.pow(t, 2) * control2.y +
                      Math.pow(t, 3) * end.y;
                      
            return new Point((int)x, (int)y);
        }
    }
    
    private static class BezierParams {
        private final double controlPointOffset;
        private final double pathNoise;
        
        public BezierParams(double controlPointOffset, double pathNoise) {
            this.controlPointOffset = controlPointOffset;
            this.pathNoise = pathNoise;
        }
    }
}
